package com.tbit.main.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONObject;
import com.tbit.common.constant.OperationPlatform;
import com.tbit.common.entity.MachineOpLog;
import com.tbit.main.constant.*;
import com.tbit.main.controller.interceptor.LoginUserContextHolder;
import com.tbit.main.dao.core.*;
import com.tbit.main.dao.log.DispatchLogDao;
import com.tbit.main.dao.log.MoveLogDao;
import com.tbit.main.dao.log.PowerChangeLogDao;
import com.tbit.main.dao.log.PowerChangeLogExpandDao;
import com.tbit.main.exception.BaseException;
import com.tbit.main.h2.pojo.ParkPoint;
import com.tbit.main.pojo.*;
import com.tbit.main.pojo.VO.BatchMoveMachineReqVO;
import com.tbit.main.pojo.VO.MachineVO;
import com.tbit.main.pojo.VO.PutMachineReqVO;
import com.tbit.main.pojo.VO.PutMachineRespVO;
import com.tbit.main.pojo.bo.BatchMoveMachineBO;
import com.tbit.main.pojo.dto.CheckMachineDTO;
import com.tbit.main.pojo.dto.ImportMachineDTO;
import com.tbit.main.service.*;
import com.tbit.main.util.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.MapUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.text.ParseException;
import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;

@Slf4j
@Service("machineService")
public class MachineServiceImpl implements MachineService {

    @Autowired
    private MachineDao machineDao;
    @Autowired
    private MachineStatusService machineStatusService;
    @Autowired
    private RideLogService rideLogService;
    @Autowired
    private ParkPointService parkPointService;
    @Autowired
    private MachineBorrowService machineBorrowService;
    @Autowired
    private GeoService geoService;
    @Autowired
    private AccountConfigService accountConfigService;
    @Autowired
    private ProhibitAreaService prohibitAreaService;
    @Autowired
    private MachineOccupyService machineOccupyService;
    @Autowired
    private AccountUserService accountUserService;
    @Autowired
    private RedisService redisService;
    @Autowired
    private BatteryService batteryService;
    @Autowired
    private MachineFunctionService machineFunctionService;
    @Autowired
    private CameraService cameraService;
    @Autowired
    private MachineAbnormalService machineAbnormalService;
    @Autowired
    private BatteryModelService batteryModelService;
    @Autowired
    private StockMachineService stockMachineService;
    @Autowired
    private MachineAttrService machineAttrService;
    @Autowired
    private HelmetBoundService helmetBoundService;
    @Autowired
    private DataService dataService;
    @Autowired
    private CalibrateService calibrateService;
    @Resource
    private MachineOpLogService machineOpLogService;
    @Resource
    private MachineTagDao machineTagDao;
    @Resource
    private TagDao tagDao;
    @Resource
    private GeoreMachineDao georeMachineDao;
    @Resource
    private MachineAbnormalDao machineAbnormalDao;
    @Resource
    private MachineFaultDao machineFaultDao;
    @Autowired
    private MoveLogDao moveLogDao;
    @Autowired
    private DispatchLogDao dispatchLogDao;
    @Autowired
    private PowerChangeLogDao powerChangeLogDao;
    @Autowired
    private HistoryService historyService;
    @Autowired
    private ThreadPoolTaskExecutor threadPoolTaskExecutor;
    @Autowired
    private PowerChangeLogExpandDao powerChangeLogExpandDao;
    @Autowired
    private MachineFaultService machineFaultService;
    @Autowired
    private RecoveryLogService recoveryLogService;
    @Resource
    private MachineManagerService machineManagerService;
    @Autowired
    private DetentionMachineBoundService detentionMachineBoundService;
    @Autowired
    private MachineNoIncomeService machineNoIncomeService;
    @Autowired
    private AppointMentService appointMentService;

    @Override
    public Machine getByMachineNO(String machineNO) {
        return machineDao.getByMachineNO(machineNO);
    }

    @Override
    public Machine getFLM(String frame, String license, String motor) {
        Map<String, Object> map = new HashMap<>();
        map.put("frame", frame);
        map.put("license", license);
        map.put("motor", motor);
        return machineDao.getFLM(map);
    }

    @Override
    public Machine getByMachineId(Integer machineId) {
        return machineDao.getByMachineId(machineId);
    }

    @Override
    public List<Machine> getByAccountId(Integer accountId) {
        return machineDao.getByAccountId(accountId);
    }

    @Override
    public List<MachineVO> getByAccountIdPag(Integer accountId, Integer machineType, Integer pageNO, Integer rowCount,
                                             Integer functionType, Integer mapType, Integer machineStatusType) {
        Map<String, Object> map = new HashMap<>();
        map.put(DaoParamConstant.accountId, accountId);
        map.put("machineType", machineType);
        map.put("pageNO", (pageNO - 1) * rowCount);
        map.put("rowCount", rowCount);
        map.put("functionType", functionType);
        map.put("machineStatusType", machineStatusType);
        List<MachineVO> machines = machineDao.getByAccountIdPag(map);

        if (CollUtil.isNotEmpty(machines)) {

            /**查询设备功能*/
            List<Integer> machineIds = machines.stream().map(Machine::getMachineId).collect(Collectors.toList());
            List<MachineFunction> machineFunctions = machineFunctionService.getMachineIdsType(machineIds, functionType);
            Map<Integer, List<MachineFunction>> mapFunction = new HashMap<>();
            if (CollUtil.isNotEmpty(machineFunctions)) {
                for (MachineFunction machineFunction : machineFunctions) {
                    if (mapFunction.containsKey(machineFunction.getMachineId())) {
                        mapFunction.get(machineFunction.getMachineId()).add(machineFunction);
                    } else {
                        List<MachineFunction> machineFunctions1 = new LinkedList<>();
                        machineFunctions1.add(machineFunction);
                        mapFunction.put(machineFunction.getMachineId(), machineFunctions1);
                    }
                }
            }

            for (Machine machine : machines) {
                MachineStatus machineStatus = dataService.getMachineStatus(machine.getMachineId());
                if (machineStatus != null) {
                    machine.setPosDt(machineStatus.getPosDt());
                    machine.setLon(machineStatus.getLon());
                    machine.setLat(machineStatus.getLat());
                    // 校准经纬度
                    Point point = new Point(machineStatus.getLon(), machineStatus.getLat());
                    calibrateService.commonCalibrate(point, MapConstant.MAP_ORI, mapType);
                    machineStatus.setLonC(point.getX());
                    machineStatus.setLatC(point.getY());
                }
                machine.setMachineFunctionList(mapFunction.get(machine.getMachineId()));
            }

            /**查询文明骑行摄像头*/
            List<String> machineNOs = machines.stream().map(Machine::getMachineNO).collect(Collectors.toList());
            List<Camera> cameras = cameraService.getMachineNOs(machineNOs);
            if (cameras != null && cameras.size() > 0) {
                Map<String, Camera> cameraMap = new HashMap<>();
                for (Camera camera : cameras) {
                    cameraMap.put(camera.getMachineNO(), Camera.functionString(camera));
                }
                for (Machine machine : machines) {
                    machine.setCamera(cameraMap.get(machine.getMachineNO()));
                }
            }
        }

        return machines;
    }

    @Override
    public void changeState(Integer machineId, Integer state) {
        Map<String, Object> params = new HashMap<>();
        params.put("machineId", machineId);
        params.put("state", state);

        machineDao.changeState(params);
    }

    @Override
    public List<Machine> getByParkPointId(Integer parkPointId) {
        Map<String, Object> params = new HashMap<>();
        params.put("parkPointId", parkPointId);
        return machineDao.getByParkPointId(params);
    }

    @Override
    public List<Machine> getByMachineNOs(List<String> machineNOs) {
        Map<String, Object> params = new HashMap<>();
        params.put("machineNOs", StringUtil.getArrayListString(machineNOs));

        return machineDao.getByMachineNOs(params);
    }

    @Override
    @Transactional(value = "coreTransactionManager")
    public void put(ParkMachine parkMachine) {
        /**删除上一个投放记录*/
        recovery(parkMachine.getMachineId());
        parkMachine.setAddTime(DateTimeUtil.getNowTime());
        machineDao.put(parkMachine);
    }

    @Override
    @Transactional(value = "coreTransactionManager")
    public void putMachine(ParkMachine parkMachine) {
        /**删除上一个投放记录*/
        recovery(parkMachine.getMachineId());

        Machine machine = getByMachineId(parkMachine.getMachineId());

        if (!machine.getState().equals(MachineStateConstant.MACHINE_STATE_GZ)) {
            /**更改成正常运营状态*/
            changeState(parkMachine.getMachineId(), MachineStateConstant.MACHINE_STATE_ZCYY);
        }

        parkMachine.setAddTime(DateTimeUtil.getNowTime());
        machineDao.put(parkMachine);
    }

    @Override
    public void recovery(Integer machineId) {
        machineDao.recovery(machineId);
    }

    @Override
    public List<Machine> getUnUseByAccountId(Integer accountId, String lastBorrowTime) {
        Map<String, Object> params = new HashMap<>();
        params.put(DaoParamConstant.accountId, accountId);
        params.put("lastBorrowTime", lastBorrowTime);
        return machineDao.getUnUseByAccountId(params);
    }

    @Override
    public void authCheck(AccountUser accountUser, String useCode, Integer accountId) {
        List<Agent> agents = accountUser.getAgents();
        Machine machine;
        /**查询设备*/
        machine = getByUseCodeAndAccountId(useCode, accountId);
        if (machine == null) {
            throw new BaseException("Machine.notExist");
        }

        /**权限判断*/
        List<Integer> agentIds = new ArrayList<>();
        for (Agent agent : agents) {
            agentIds.add(agent.getAccountId());
        }

        //权限不足改为车辆不存在的提示语
        if (!agentIds.contains(machine.getAccountId())) {
            throw new BaseException("Machine.notExist");
        }

    }


    @Override
    public void auth(List<Agent> agents, Integer machineId) {
        /**查询设备*/
        Machine machine = getByMachineId(machineId);

        if (machine == null) {
            throw new BaseException("Machine.notExist");
        }

        /**权限判断*/
        List<Integer> agentIds = new ArrayList<>();
        for (Agent agent : agents) {
            agentIds.add(agent.getAccountId());
        }

        if (!agentIds.contains(machine.getAccountId())) {
            throw new BaseException("System.noPower");
        }
    }

    @Override
    public void auth(List<Agent> agents, Machine machine) {
        if (machine == null) {
            throw new BaseException("Machine.notExist");
        }
        /**权限判断*/
        List<Integer> agentIds = new ArrayList<>();
        for (Agent agent : agents) {
            agentIds.add(agent.getAccountId());
        }

        if (!agentIds.contains(machine.getAccountId())) {
            throw new BaseException("System.noPower");
        }
    }

    @Override
    public Boolean auth(Integer accountId) {
        AccountUser loginUser = LoginUserContextHolder.getLoginUser();

        List<Integer> agents = loginUser.getAgents().stream().map(Agent::getAccountId).collect(Collectors.toList());

        return !agents.contains(accountId);
    }

    @Override
    public void auth(Machine machine) {
        AccountUser loginUser = LoginUserContextHolder.getLoginUser();
        auth(loginUser.getAgents(), machine);
    }

    @Override
    public List<String> authBatch(List<Machine> machines) {
        List<String> noRightUserCodes = new ArrayList<>();

        AccountUser loginUser = LoginUserContextHolder.getLoginUser();

        List<Integer> agents = loginUser.getAgents().stream().map(Agent::getAccountId).collect(Collectors.toList());
        for (Machine machine : machines) {
            if (!agents.contains(machine.getAccountId())) {
                noRightUserCodes.add(machine.getUserCode());
            }
        }

        return noRightUserCodes;
    }

    @Override
    public ParkMachine getParkId(Integer machineId) {
        return machineDao.getParkId(machineId);
    }

    @Override
    public MachineInfo getMachineInfo(Integer machineId) throws ParseException {
        MachineInfo machineInfo = new MachineInfo();

        /**查询设备是否存在*/
        Machine machine = getByMachineId(machineId);
        if (machine == null) {
            throw new BaseException("Machine.notExist");
        }
        machineInfo.setMachine(machine);
        List<TagBaseInfo> tagBaseInfos = tagDao.getTagByMachineId(machineId);
        if (CollectionUtils.isNotEmpty(tagBaseInfos)) {
            machineInfo.setBindTags(tagBaseInfos);
            machineInfo.parse();
        }

        MachineShowStatus machineShowStatus = new MachineShowStatus();
        machineShowStatus.setMachineBusState(1);
        machineShowStatus.setMachineMainState(machine.getState());
        machineShowStatus.setMachineLockState(1);
        machineShowStatus.setMachineParkState(1);

        MachineStatusBorrow machineStatusBorrow = new MachineStatusBorrow();
        machineStatusBorrow.setLastBorrowTime(machine.getLastBorrowTime());
        machineInfo.setMachineStatusBorrow(machineStatusBorrow);
        // 库存状态，0：不在库存，1：在库存
        Integer stock = stockMachineService.countByMachineId(machine.getMachineId());
        machineStatusBorrow.setStock(stock > 0);

        /**查询最后状态*/
        MachineStatus machineStatus = machineStatusService.getByMachineId(machineId);
        if (machineStatus != null) {
            /**用户码、中控码*/
            machineStatus.setUserCode(machine.getUserCode());
            machineStatus.setMachineNO(machine.getMachineNO());

            Battery battery = batteryService.getByMachineId(machineInfo.getMachine().getMachineId());
            if (battery != null) {
                machineStatus.setBatteryNO(battery.getBatteryNO());
                machineInfo.getMachine().setBatteryNO(battery.getBatteryNO());
            }
            machineInfo.setMachineStatus(machineStatus);

            /**查询车辆锁状态*/
            String json = redisService.getGetWay(RedisUtil.getTerHashId(machine.getMachineNO()), RedisConstant.REDIS_TER_LAST_STATUS);
            TerLastStatus terLastStatus = JSONObject.parseObject(json, TerLastStatus.class);
            Boolean lock;
            if (terLastStatus == null) {
                lock = IntegerUtil.getLockState(0);//无信号车辆
            } else {

                lock = IntegerUtil.getLockState(terLastStatus.getCarStatus());
            }

            machineShowStatus.setMachineLockState(lock ? 1 : 0);
        } else {
            throw new BaseException("MachineState.not.gps");
        }

        /**查询借出信息*/
        RideLog rideLog = rideLogService.findLastByMachineId(machineId);
        if (rideLog != null) {
            /**计算骑行时长*/
            String startTime = rideLog.getStartTime();
            String endTime = DateTimeUtil.getNowTime();
            MachineBorrow machineBorrow = machineBorrowService.getByMachineId(machineId);
            if (machineBorrow == null && rideLog.getEndTime() != null) {
                endTime = rideLog.getEndTime();
            }

            Integer rideTime = DateTimeUtil.getMinutes(startTime, endTime);
            rideLog.setRideTime(rideTime);

            machineInfo.setRideLog(rideLog);
        }

        /**查询归属站点信息*/
        ParkPoint parkPoint = parkPointService.getByMachineId(machineId);
        if (parkPoint != null) {
            machineInfo.setParkPoint(parkPoint);
        }


        /**查询车辆当前租车信息*/
        MachineBorrow machineBorrow = machineBorrowService.getByMachineId(machineId);
        if (machineBorrow != null) {
            machineShowStatus.setMachineBusState(2);
            /**查询车辆临停信息*/
            Park park = getParkByMachineId(machineId);
            if (park != null) {
                machineShowStatus.setMachineBusState(3);
            }
        }

        /**车辆运维占用信息*/
        MachineOccupy machineOccupy = machineOccupyService.getByMachineId(machineId);
        if (machineOccupy != null) {
            AccountUser au = accountUserService.getById(machineOccupy.getAccountUserId());
            if (au != null) {
                machineOccupy.setName(au.getName());
            }

            machineInfo.setMachineOccupy(machineOccupy);
        }

        /**检测是否在站点*/
        /**是否在区域内*/
        if (machineStatus != null) {
            List<Geo> geos = geoService.getByAccountId(machine.getAccountId());
            if (geos.size() > 0) {
                Geo geo = geos.get(0);
                Boolean isInArea = GeoUtil.IsPtInPoly(new Point(machineStatus.getLon(), machineStatus.getLat()), GeoUtil.getPoints(geo.getPoints()));
                //0:站外；1：站内；2：超区
                if (isInArea) {
                    /**判断是站外还是禁停区内*/
                    AccountConfig ac = accountConfigService.getByAccountId(machine.getAccountId());
                    if (ac == null || ac.getReturnModel() == 0) {
                        ParkPoint parkPointIn = parkPointService.checkInParkPoint(machine.getAccountId(), new Point(machineStatus.getLon(), machineStatus.getLat()), 150, 100);
                        machineShowStatus.setMachineParkState(parkPointIn == null ? 0 : 1);
                    } else {
                        /**判断是否禁停区内*/
                        ProhibitArea prohibitArea = prohibitAreaService.checkInProhibitArea(machine.getAccountId(), new Point(machineStatus.getLon(), machineStatus.getLat()), 3000);
                        machineShowStatus.setMachineParkState(prohibitArea == null ? 0 : 1);
                    }
                } else {
                    machineShowStatus.setMachineParkState(2);
                }
            }
        }

        machineInfo.setMachineShowStatus(machineShowStatus);

        /**查询设备功能*/
        List<MachineFunction> machineFunctions = machineFunctionService.getMachineId(machineId);
        machineInfo.getMachine().setMachineFunctionList(machineFunctions);

        /**查询文明骑行摄像头*/
        Camera camera = cameraService.getMachineNO(machine.getMachineNO());
        machineInfo.getMachine().setCamera(camera);

        MachineAbnormal machineAbnormal = machineAbnormalService.getByMachineIdAndType(machine.getMachineId(), MachineAbnormalConstant.MACHINE_ABNORMAL_CCQY);
        if (machineAbnormal != null) {
            machineInfo.getMachineStatus().setAbnormalTime(machineAbnormal.getAbnormalTime());
        }


        /**查询车辆绑定电池类型id*/
        MachineBatteryModel machineBatteryModel = batteryModelService.getMachineId(machineInfo.getMachine().getMachineId());
        if (machineBatteryModel != null) {

            /**查询主电池方案*/
            BatteryModel batteryModel = batteryModelService.getByModelId(machineBatteryModel.getBatteryModelId());
            if (batteryModel != null) {
                machineInfo.getMachineStatus().setBatteryType(batteryModel.getBatteryType());
            } else {
                machineInfo.getMachineStatus().setBatteryType(BatteryConstant.Battery_type_dy);
            }

            //判断主电池是否为氢电池
            if (batteryModel != null && Objects.equals(BatteryConstant.Battery_type_qdc, batteryModel.getBatteryType())) {
                if (machineBatteryModel.getSecondaryBattertId() != null) {
                    //查询电压
                    MachineEvent machineEvent = machineAttrService.getMachineEvent(machineInfo.getMachine().getMachineNO(), "tLiSOC");
                    Integer secondaryBattery = Optional.ofNullable(machineEvent)
                            .map(MachineEvent::getEventValue)
                            .filter(StringUtils::isNotBlank)
                            .map(Integer::parseInt)
                            .orElse(0);
                    machineInfo.getMachineStatus().setSecondaryBattery(secondaryBattery);

                }
            }
        }

        Helmet helmet = helmetBoundService.getMachineId(machine.getMachineId());
        if (helmet != null) {
            machineInfo.getMachineStatus().setHelmetSoc(helmet.getSoc());
        }

        /*获取超长时间订单*/
        Map<Integer, String> longOrderTime = machineManagerService.getLongOrderTime(new ArrayList<>(Collections.singletonList(machineId)), machine.getAccountId());
        machineStatus.setLongOrderHour(Objects.isNull(longOrderTime) ? null : longOrderTime.get(machineId));

        return machineInfo;
    }

    @Override
    public Integer getCountByAccountId(Integer accountId) {
        return machineDao.getCountByAccountId(accountId);
    }

    @Override
    public Integer getCountByAccountIdType(Integer accountId, Integer machineType, Integer function, Integer machineStatusType) {
        Map<String, Object> map = new HashMap<>();
        map.put(DaoParamConstant.accountId, accountId);
        map.put("machineType", machineType);
        map.put("function", function);
        map.put("machineStatusType", machineStatusType);
        return machineDao.getCountByAccountIdType(map);
    }

    @Override
    public List<Map<String, Object>> getCountByAccountIds(List<Integer> accountId) {
        Map<String, Object> params = new HashMap<>();
        params.put(DaoParamConstant.accountId, StringUtil.getListString(accountId));
        return machineDao.getCountByAccountIds(params);
    }

    @Override
    public Park getParkByMachineId(Integer machineId) {
        return machineDao.getParkByMachineId(machineId);
    }

    @Override
    public List<Machine> getUseingByAccountId(Integer accountId) {
        return machineDao.getUseingByAccountId(accountId);
    }

    @Override
    public List<Machine> getUseingByRegionId(List<Integer> regionId) {
        return machineDao.getUseingByRegionId(StringUtil.getListString(regionId));
    }

    @Override
    public List<Machine> getAll() {
        return machineDao.getAll();
    }

    @Override
    public List<Machine> getState(List<Integer> accountIds) {
        return machineDao.getState(StringUtil.getListString(accountIds));
    }

    @Override
    public Machine getByUseCode(String userCode) {
        Map<String, Object> params = new HashMap<>();
        params.put("userCode", userCode);
        return machineDao.getByUseCode(params);
    }

    @Override
    public List<Machine> getByUserCodes(List<String> userCodes) {
        if (CollectionUtil.isEmpty(userCodes)) {
            return Collections.emptyList();
        }
        return machineDao.getByUserCodeList(userCodes);
    }

    @Override
    public List<Machine> getByUserCodesAndAccountId(List<String> userCodes, Integer accountId) {
        Map<String, Object> params = new HashMap<>();
        params.put(DaoParamConstant.accountId, accountId);
        params.put("userCodes", StringUtil.getArrayListString(userCodes));
        return machineDao.getByUserCodesAndAccountId(params);
    }

    @Override
    public List<Machine> getByAccountIds(List<Integer> accountIds) {
        Map<String, Object> params = new HashMap<>();
        params.put(DaoParamConstant.accountIds, StringUtil.getListString(accountIds));
        return machineDao.getByAccountIds(params);
    }

    @Override
    public List<Machine> getUseingByAccountIds(List<Integer> accountIds) {
        Map<String, Object> params = new HashMap<>();
        params.put(DaoParamConstant.accountId, StringUtil.getListString(accountIds));
        return machineDao.getUseingByAccountIds(params);
    }

    @Override
    public List<Integer> getUseingIdsByAccountIds(List<Integer> accountIds) {
        Map<String, Object> params = new HashMap<>();
        params.put(DaoParamConstant.accountId, StringUtil.getListString(accountIds));
        return machineDao.getUseingIdsByAccountIds(params);
    }

    @Override
    public void boundUpdate(Integer machineId, String userCode, String machineNO, String frame, String license, String motor, String remark) {
        Map<String, Object> params = new HashMap<>();
        params.put("machineId", machineId);
        params.put("userCode", userCode);
        params.put("machineNO", machineNO);
        params.put("frame", frame);
        params.put("license", license);
        params.put("motor", motor);
        params.put("remark", remark);
        machineDao.boundUpdate(params);
    }

    @Override
    public Integer getByAccountDate(Integer accountId, String date) {
        Map<String, Object> params = new HashMap<>();
        params.put(DaoParamConstant.accountId, accountId);
        params.put("date", date);
        return machineDao.getByAccountDate(params);
    }


    @Override
    public void updateLastBorrowTime(Integer machineId) {
        Map<String, Object> params = new HashMap<>();
        params.put("machineId", machineId);
        params.put("lastBorrowTime", DateTimeUtil.getNowTime());

        machineDao.updateLastBorrowTime(params);
    }

    @Override
    public List<Machine> getUnLock(List<String> machineNOs) {
        Map<String, Object> params = new HashMap<>();
        params.put("machineNOs", StringUtil.getArrayListString(machineNOs));
        return machineDao.getUnLock(params);
    }

    @Override
    public Integer getCountByBrand(Integer accountId) {
        return machineDao.getCountByBrand(accountId);
    }

    @Override
    public Integer getCountByBrandByAccountId(List<Integer> accountId) {
        Map<String, Object> map = new HashMap<>();
        map.put(DaoParamConstant.accountId, StringUtil.getListString(accountId));
        return machineDao.getCountByBrandByAccountId(map);
    }

    @Override
    public List<Machine> getByMachineIds(List<Integer> machineIds) {
        Map<String, Object> params = new HashMap<>();
        params.put("machineIds", StringUtil.getListString(machineIds));
        return machineDao.getByMachineIds(params);
    }

    @Override
    public List<Machine> getByMachineIdsAll(List<Integer> machineIds) {
        Map<String, Object> params = new HashMap<>();
        params.put("machineIds", StringUtil.getListString(machineIds));
        return machineDao.getByMachineIdsAll(params);
    }

    @Override
    public Integer getOccupy(Integer machineId) {
        return machineDao.getOccupy(machineId);
    }

    @Override
    public List<String> getAccountIdMachine(Integer accountId) {
        return machineDao.getAccountIdMachine(accountId);
    }

    ;

    @Override
    public List<Map<String, Object>> getGroupByDay(List<Integer> accountIds) {
        Map<String, Object> map = new HashMap<>();
        map.put(DaoParamConstant.accountId, StringUtil.getListString(accountIds));
        return machineDao.getGroupByDay(map);
    }

    @Override
    public List<Map<String, Object>> getGroupByAccountId() {
        return machineDao.getGroupByAccountId();
    }

    @Override
    public Integer getByParkPointIds(Integer parkPointId) {
        Map<String, Object> params = new HashMap<>();
        params.put("parkPointId", parkPointId);
        return machineDao.getByParkPointIds(params);
    }

    @Override
    public Integer getByAccountIdType(Integer accountId, Integer state) {
        Map<String, Object> params = new HashMap<>();
        params.put(DaoParamConstant.accountId, accountId);
        params.put("state", state);
        return machineDao.getByAccountIdType(params);
    }

    @Override
    public List<Machine> selectMachineListByAccountIdAndState(Integer accountId, Integer state) {
        return machineDao.selectMachineListByAccountIdAndState(accountId, state);
    }

    @Override
    public List<Machine> selectMachineListByRegionIdAndState(Integer regionId, Integer state) {
        return machineDao.selectMachineListByRegionIdAndState(regionId, state);
    }

    @Override
    public Integer getByRegionIdType(Integer regionId, Integer state) {
        Map<String, Object> params = new HashMap<>();
        params.put("regionId", regionId);
        params.put("state", state);
        return machineDao.getByRegionIdType(params);
    }

    @Override
    public List<Integer> getMachineIdByNOs(List<String> machineNOs, Integer machineType) {
        return machineDao.getMachineIdByNOs(StringUtil.getStringListString(machineNOs), machineType);
    }

    @Override
    public List<String> getMachineNOByIds(List<Integer> machineIds, Integer machineType) {
        return machineDao.getMachineNOByIds(StringUtil.getListString(machineIds), machineType);
    }

    @Override
    public List<String> getUserCodeByMachineNo(List<String> machineNos) {
        return machineDao.getUserCodeByMachineNo(StringUtil.getStringListString(machineNos));
    }

    @Override
    public List<Map<String, Object>> getAccountLast(String lastBorrowTime) {
        return machineDao.getAccountLast(lastBorrowTime);
    }

    @Override
    public List<Map<String, Object>> getAccountEvent(String startTime, String endTime, Integer count) {
        Map<String, Object> map = new HashMap<>();
        map.put(DaoParamConstant.startTime, startTime);
        map.put(DaoParamConstant.endTime, endTime);
        map.put("count", count);
        return machineDao.getAccountEvent(map);
    }

    @Override
    public Integer parkMachineInside(Integer machineId, Integer parkPointId, Integer inside) {
        Map<String, Object> map = new HashMap<>();
        map.put("machineId", machineId);
        map.put("parkPointId", parkPointId);
        map.put("inside", inside);
        return machineDao.ParkMachineInside(map);
    }

    @Override
    public List<Integer> getExist(List<Integer> list, String lastBorrowTime) {
        Map<String, Object> map = new HashMap<>();
        map.put("list", list);
        map.put("lastBorrowTime", lastBorrowTime);
        return machineDao.getExist(map);
    }

    @Override
    public Machine getByUseCodeAndAccountId(String userCode, Integer accountId) {
        Map<String, Object> params = new HashMap<>();
        params.put("userCode", userCode);
        params.put("accountId", accountId);
        return machineDao.getByUseCode(params);
    }

    @Override
    public void changeStateBatch(List<String> userCodeS) {
        machineDao.changeStateBatch(userCodeS);
    }

    @Override
    public String getByMachineIdTag(Integer machineId) {
        return machineDao.getByMachineIdTag(machineId);
    }

    @Override
    public List<PutMachineRespVO> putMachine(PutMachineReqVO reqVO) {
        List<String> moveUserCodes = ListUtil.convertList(reqVO.getUserCodes(), String::valueOf);
        List<Machine> machines = getByUserCodesAndAccountId(moveUserCodes, reqVO.getAccountId());
        return PutMachineRespVO.of(checkMachine(moveUserCodes, machines));
    }

    @Override
    public Map<String, String> checkMachine(List<String> userCodes, List<Machine> machines) {
        Map<String, String> result = new HashMap<>();

        List<String> userCodesExist = machines.stream().map(Machine::getUserCode).collect(Collectors.toList());

        List<String> noRightUserCodes = authBatch(machines);

        for (String userCode : userCodes) {
            if (!userCodesExist.contains(userCode)) {
                result.put(userCode, "车辆不存在");
                continue;
            }

            if (noRightUserCodes.contains(userCode)) {
                result.put(userCode, "无权操作");
            }
        }
        return result;
    }

    @Override
    public List<PutMachineRespVO> batchMoveMachine(BatchMoveMachineReqVO reqVO) {
        if (reqVO.getTargetAccountId() != null && auth(reqVO.getTargetAccountId())) {
            throw new BaseException("无权操作目标区域");
        }

        List<String> moveUserCodes = ListUtil.convertList(reqVO.getUserCodes(), String::valueOf);
        List<Machine> machines = getByUserCodesAndAccountId(moveUserCodes, reqVO.getAccountId());

        List<Integer> machineIds = machines.stream().map(Machine::getMachineId).collect(Collectors.toList());
        List<Integer> borrowMachineIds = machineBorrowService.getByMachineIds(machineIds)
                .stream().map(MachineBorrow::getMachineId).collect(Collectors.toList());
        List<Integer> occupyMachineIds = machineOccupyService.getByMachineIds(machineIds)
                .stream().map(MachineOccupy::getMachineId).collect(Collectors.toList());

        Map<String, String> result = checkMachine(moveUserCodes, machines);
        Map<String, Integer> machineMap = machines.stream().collect(Collectors.toMap(Machine::getUserCode, Machine::getMachineId));
        List<Integer> finallyMoveMachineIds = new ArrayList<>();
        for (String moveUserCode : moveUserCodes) {
            // 校验过了
            if (result.containsKey(moveUserCode)) {
                continue;
            }

            Integer machineId = machineMap.get(moveUserCode);

            if (borrowMachineIds.contains(machineId)) {
                result.put(moveUserCode, "骑行中");
                continue;
            }

            finallyMoveMachineIds.add(machineId);
        }

        if (CollUtil.isNotEmpty(occupyMachineIds)) {
            machineOccupyService.batchUnOccupy(occupyMachineIds);
        }

        if (CollUtil.isNotEmpty(finallyMoveMachineIds)) {
            machineDao.batchMoveMachine(new BatchMoveMachineBO(StringUtil.getListString(finallyMoveMachineIds), reqVO.getTargetAccountId(), reqVO.getState()));
            /**划拨车辆清除车辆状态*/
            this.clearMachineStatus(finallyMoveMachineIds);
        }
        return PutMachineRespVO.of(result);
    }

    @Override
    public void clearMachineStatus(List<Integer> machineIdList) {
        Map<String, Object> params = new HashMap<>();
        params.put("machineIds", StringUtil.getListString(machineIdList));
        List<Machine> machineList = machineDao.getByMachineIdsAll(params);
        List<String> userCodeList = machineList.stream().map(Machine::getUserCode).collect(Collectors.toList());
        /**清除故障状态*/
        machineFaultService.batchClearMachineFaultById(machineIdList);
        /**清除流转状态*/
        recoveryLogService.updateBatchByMachineList(machineIdList, RecoveryLogConstant.RECOVERYLOG_STATE_FALSE,
                "划拨车辆批量清除回收状态");
        detentionMachineBoundService.deleteBatchByMachineList(machineIdList);
        stockMachineService.deleteBatchByMachineList(machineIdList,  "划拨车辆批量清除库存状态");
        georeMachineDao.deleteByMachineIds(machineIdList);
        /**清除订单状态*/
        machineDao.clearBatchLastUseTimeByMachineIds(machineIdList);
        machineNoIncomeService.deleteBatchByMachineList(userCodeList);
        /**清除骑行状态*/
        appointMentService.deleteBatchByMachineIds(machineIdList);
    }


    /**
     * 校验设备信息
     * @param dto dto
     * @return Result
     */
    @Override
    public Result<Object> checkMachine(CheckMachineDTO dto) {
        if (StrUtil.isEmpty(dto.getMachineNo()) || StrUtil.isEmpty(dto.getUserCode())){
            return Result.error("设备编号和车辆编号不允许为空");
        }
        if (machineDao.countByUserCode(dto.getUserCode()) > 0){
            return Result.error("车辆编号已存在");
        }
        if (machineDao.countByMachineNo(dto.getMachineNo()) > 0){
            return Result.error("设备编号已存在");
        }
        if (StrUtil.isNotBlank(dto.getLicense()) && machineDao.countByLicense(dto.getLicense()) > 0){
            return Result.error("车牌号已存在");
        }
        if (StrUtil.isNotBlank(dto.getFrame()) && machineDao.countByFrame(dto.getFrame()) > 0){
            return Result.error("车架号已存在");
        }
        if (StrUtil.isNotBlank(dto.getMotor()) && machineDao.countByMotor(dto.getMotor()) > 0){
            return Result.error("电机号已存在");
        }
        return Result.success();
    }

    /**
     * 批量新增
     * @param dto dto
     * @return Result
     */
    @Override
    public Result<List<String>> importMachine(ImportMachineDTO dto, AccountUser account) {
        if (Objects.isNull(dto.getAccountId())){
            return Result.error("请选择区域");
        }
        BatteryModel batteryModel = batteryModelService.getByModelId(dto.getBatteryModelId());
        if (null == batteryModel) {
            throw new BaseException("电池方案不存在");
        }
        if (dto.getMachineType() == null) {
            dto.setMachineType(0);
        }
        if (CollectionUtil.isEmpty(dto.getCheckMachineDTOList())){
            return Result.error("请选择要导入的设备");
        }
        Set<String> failUserCode = machineDeduplication(dto.getCheckMachineDTOList(), 0);
        List<CheckMachineDTO> checkMachineDTOList = dto.getCheckMachineDTOList();
        List<CheckMachineDTO> filteredList = checkMachineDTOList.stream()
                .filter(item -> !failUserCode.contains(item.getUserCode()))
                .collect(Collectors.toList());
        //插入数据
        if (CollectionUtil.isEmpty(filteredList)){
            return Result.success(new ArrayList<>(failUserCode));
        }
        machineDao.batchAddMachine(dto.getAccountId(), dto.getMachineType(), dto.getPutIn(), filteredList);
        Map<Integer, CheckMachineDTO> machineIdMap = filteredList.stream().collect(Collectors.toMap(CheckMachineDTO::getMachineId, item -> item));
        // id绑定电池方案
        List<Integer> machineIds = filteredList.stream().map(CheckMachineDTO::getMachineId).collect(Collectors.toList());
        batteryModelService.batchAdd(machineIds,dto.getBatteryModelId());

        // 插入车辆操作日志
        List<MachineOpLog> machineOpLogs = filteredList.stream()
                .map(f -> MachineOpLog.builder()
                        .accountId(dto.getAccountId())
                        .machineId(f.getMachineId())
                        .machineNO(f.getMachineNo())
                        .userCode(f.getUserCode())
                        .operation("导入车辆信息")
                        .opType("新增")
                        .opUser(account.getUserName())
                        .opUserPhone(account.getPhone())
                        .opPlatform(3)
                        .result(true)
                        .opTime(LocalDateTime.now())
                        .build())
                .collect(Collectors.toList());

        machineOpLogService.insertBatch(machineOpLogs);

        //设备功能配置
        if (StrUtil.isNotEmpty(dto.getFunctionList())) {
            String[] split = dto.getFunctionList().split(",");
            List<MachineFunction> functions = Arrays.stream(split)
                    .flatMap(functionType -> machineIds.stream().map(machineId -> {
                        MachineFunction machineFunction = new MachineFunction();
                        machineFunction.setFunctionName(MachineFunctionConstant.FUNCTION_NAME_MAP.get(Integer.parseInt(functionType)));
                        machineFunction.setFunctionType(Integer.parseInt(functionType));
                        machineFunction.setFunctionValue(1);
                        machineFunction.setMachineId(machineId);
                        machineFunction.setUpdateTime(DateUtil.now());
                        return machineFunction;
                    })).collect(Collectors.toList());
            if (CollectionUtils.isNotEmpty(functions)) {
                machineFunctionService.batchAdd(functions);
            }
            if (Arrays.asList(split).contains(String.valueOf(MachineFunctionConstant.MACHINE_TYPE_WMQX))) {
                List<Camera> cameraList = checkMachineDTOList.stream().map(x -> new Camera(dto.getAccountId(), x.getMachineNo(), DateUtil.now())).collect(Collectors.toList());
                machineFunctionService.addCameraBatch(cameraList);
            }
            // 插入车辆操作日志-功能配置
            List<MachineOpLog> machineOpLog = functions.stream()
                    .map(x -> MachineOpLog.builder()
                            .accountId(dto.getAccountId())
                            .machineId(x.getMachineId())
                            .userCode(machineIdMap.get(x.getMachineId()).getUserCode())
                            .machineNO(machineIdMap.get(x.getMachineId()).getMachineNo())
                            .operation("功能配置-" + MachineFunctionConstant.FUNCTION_NAME_MAP.get(x.getFunctionType()))
                            .opType("添加")
                            .opUser(account.getUserName())
                            .opUserPhone(account.getPhone())
                            .opPlatform(OperationPlatform.MANAGER.code)
                            .result(true)
                            .opTime(LocalDateTime.now())
                            .build())
                    .collect(Collectors.toList());
            machineOpLogService.insertBatch(machineOpLog);
        }
        if (CollectionUtil.isNotEmpty(failUserCode)){
            return Result.success(new ArrayList<>(failUserCode));
        }
        return Result.success();
    }


    /**
     * 设备信息去重
     * @param machineInfoList 设备信息
     * @param type 0：新增 1：修改
     * @return set
     */
    public Set<String> machineDeduplication(List<CheckMachineDTO> machineInfoList, Integer type) {

        Map<String, CheckMachineDTO> machineNoMap = machineInfoList.stream().filter(item -> StrUtil.isNotEmpty(item.getMachineNo())).collect(Collectors.toMap(CheckMachineDTO::getMachineNo, item -> item));
        Map<String, CheckMachineDTO> licenseMap = machineInfoList.stream().filter(item -> StrUtil.isNotEmpty(item.getLicense())).collect(Collectors.toMap(CheckMachineDTO::getLicense, item -> item));
        Map<String, CheckMachineDTO> frameMap = machineInfoList.stream().filter(item -> StrUtil.isNotEmpty(item.getFrame())).collect(Collectors.toMap(CheckMachineDTO::getFrame, item -> item));
        Map<String, CheckMachineDTO> matorMap = machineInfoList.stream().filter(item -> StrUtil.isNotEmpty(item.getMotor())).collect(Collectors.toMap(CheckMachineDTO::getMotor, item -> item));

        Set<String> filaUserCode = new HashSet<>();

        List<String> mnoList = new LinkedList<>();
        List<String> codeList = new LinkedList<>();
        List<String> frameList = new LinkedList<>();
        List<String> licenseList = new LinkedList<>();
        List<String> motorList = new LinkedList<>();
        for (CheckMachineDTO item : machineInfoList) {
            /**长度校验*/
            machineCheck(item);
            mnoList.add(item.getMachineNo());
            codeList.add(item.getUserCode());
            if (StrUtil.isNotEmpty(item.getFrame())) {
                frameList.add(item.getFrame());
            }
            if (StrUtil.isNotEmpty(item.getLicense())) {
                licenseList.add(item.getLicense());
            }
            if (StrUtil.isNotEmpty(item.getMotor())) {
                motorList.add(item.getMotor());
            }
        }

        // 车辆编号是否存在
        List<String> codeExist = machineDao.cntMachineByUserCode(codeList);
        if (CollectionUtil.isNotEmpty(codeExist) && type == 0) {
            filaUserCode.addAll(codeExist);
        }

        // 设备编号是否存在
        List<String> mnoExist = machineDao.cntMachineByMachineNO(mnoList);
        for (String s : mnoExist) {
            filaUserCode.add(machineNoMap.get(s).getUserCode());
        }

        //车架号是否存在
        if (CollectionUtil.isNotEmpty(frameList)) {
            List<String> frameExist = machineDao.cntMachineByFrame(frameList);
            for (String s : frameExist) {
                filaUserCode.add(frameMap.get(s).getUserCode());
            }
        }
        if (CollectionUtil.isNotEmpty(licenseList)) {
            List<String> licenseExist = machineDao.cntMachineByLicense(licenseList);
            for (String s : licenseExist) {
                filaUserCode.add(licenseMap.get(s).getUserCode());
            }
        }
        if (CollectionUtil.isNotEmpty(motorList)) {
            List<String> motorExist = machineDao.cntMachineByMotor(motorList);
            for (String s : motorExist) {
                filaUserCode.add(matorMap.get(s).getUserCode());
            }
        }
        return filaUserCode;
    }


    /**
     * 设备信息长度限制
     * @param item
     */
    public void machineCheck(CheckMachineDTO item) {
        if (item.getUserCode() != null && item.getUserCode().length() >= 25) {
            throw new BaseException("车辆编号超出最大长度限制");
        }
        if (item.getMachineNo() != null && item.getMachineNo().length() >= 25) {
            throw new BaseException("设备编号超出最大长度限制");
        }
        if (item.getFrame() != null && item.getFrame().length() >= 25) {
            throw new BaseException("车架号超出最大长度限制");
        }
        if (item.getLicense() != null && item.getLicense().length() >= 25) {
            throw new BaseException("车牌号超出最大长度限制");
        }
        if (item.getMotor() != null && item.getMotor().length() >= 50) {
            throw new BaseException("电机号超出最大长度限制");
        }
    }

    @Override
    public MachineVO getByUseCodeAndMachineStatus(String userCode, Integer machineStatusType) {
        return machineDao.getByUseCodeAndMachineStatus(userCode, machineStatusType);
    }

    /**
     * @description: 获取车辆的异常、故障信息
     * @author: mo.shanyong
     * @date: 2025/4/11 16:34
     * @param: machineIdList 车辆id
     * @return: java.util.Map<java.lang.Integer, java.util.Map < java.lang.String, java.util.List < java.lang.Integer>>>
     */
    @Override
    public Map<Integer, Map<String, List<String>>> getMachineFaultAndAbnormal(List<Integer> machineIdList) {
        Map<Integer, Map<String, List<String>>> returnMap = new HashMap<>();
        Map<Integer, List<MachineAbnormal>> machineAbnormalMap = new HashMap<>();
        Map<Integer, List<MachineFault>> machineFaultMap = new HashMap<>();
        //异常
        List<MachineAbnormal> machineAbnormalList = machineAbnormalDao.getByMachineIds(StringUtil.getListString(machineIdList));
        if (CollectionUtils.isNotEmpty(machineAbnormalList)){
            machineAbnormalMap = machineAbnormalList.stream().collect(Collectors.groupingBy(MachineAbnormal::getMachineId));
        }
        //故障
        List<MachineFault> machineFaultList = machineFaultDao.selectByMachineIds(StringUtil.getListString(machineIdList));
        if (CollectionUtils.isNotEmpty(machineFaultList)){
            machineFaultMap = machineFaultList.stream().collect(Collectors.groupingBy(MachineFault::getMachineId));
        }
        if (MapUtils.isEmpty(machineAbnormalMap) && MapUtils.isEmpty(machineFaultMap)){
            return returnMap;
        }
        for (Integer machineId : machineIdList) {
            Map<String, List<String>> map = new HashMap<>();
            //异常
            List<MachineAbnormal> machineAbnormals = machineAbnormalMap.get(machineId);
            if (CollectionUtils.isNotEmpty(machineAbnormals)) {
                List<String> abnormalTypeNameList = new ArrayList<>();
                List<Integer> abnormalTypeList = machineAbnormals.stream().map(MachineAbnormal::getAbnormalType).collect(Collectors.toList());
                for (Integer abnormalType : abnormalTypeList) {
                    abnormalTypeNameList.add(MachineAbnormalConstant.parse(abnormalType));
                }
                map.put("abnormal", abnormalTypeNameList);
            }
            //故障
            List<MachineFault> machineFaults = machineFaultMap.get(machineId);
            if (CollectionUtils.isNotEmpty(machineFaults)) {
                this.addFault(machineFaults, map);
            }
            if (MapUtils.isEmpty(map)){
                continue;
            }
            returnMap.put(machineId,map);

        }
        return returnMap;
    }

    /**
     * @description: 设置车辆故障信息
     * @author: mo.shanyong
     * @date: 2025/4/17 16:47
     * @param: machineFaults 车辆故障
     * @param: map
     */

    private Set<String> addFault(List<MachineFault> machineFaults, Map<String, List<String>> map) {
        Set<String> faultTypeNameSet = new HashSet<>();
        for (MachineFault machineFault : machineFaults) {
            String[] split = machineFault.getFaults().split(",");
            for (String s : split) {
                if (s.matches("\\d+")) {
                    faultTypeNameSet.add(FaultType.parseFaults(s));
                }else {
                    faultTypeNameSet.add(s);
                }
            }
        }
        map.put("fault",new ArrayList<>(faultTypeNameSet));
        return faultTypeNameSet;
    }

    /**
     * @description: 获取车辆全部信息包括最新的挪车、调度、换电、故障等
     * @author: mo.shanyong
     * @date: 2025/4/18 9:10
     * @param: machineId 车辆id
     * @return: com.tbit.main.pojo.MachineInfo
     */
    @Override
    public MachineInfo getMachineInfoV2(Integer machineId) {
        MachineInfo machineInfo = new MachineInfo();
        /**查询设备是否存在*/
        Machine machine = getByMachineId(machineId);
        if (machine == null) {
            throw new BaseException("Machine.notExist");
        }
        machineInfo.setMachine(machine);

        CompletableFuture<Void> runFuture1 = CompletableFuture.runAsync(() -> {
            //库存信息和标签
            this.setMachineStockAndTag(machineInfo);
        },threadPoolTaskExecutor).exceptionally(e -> {
            log.info("getMachineInfoV2------>获取车辆库存信息和车辆标签异常，e",e);
            return null;
        }).thenRunAsync(() -> {
            /**设置车辆状态*/
            this.setMachineState(machineInfo);
        },threadPoolTaskExecutor).exceptionally(e -> {
            log.info("getMachineInfoV2------>获取车辆状态异常:e",e);
            return null;
        });

        CompletableFuture<Void> runFuture2 = CompletableFuture.runAsync(() -> {
            /**查询车辆最新订单*/
            try {
                this.setLastRideLog(machineInfo);
            } catch (ParseException e) {
                throw new RuntimeException(e);
            }
        },threadPoolTaskExecutor).exceptionally(e -> {
            log.info("getMachineInfoV2------>获取车辆最新订单异常:e",e);
            return null;
        }).thenRunAsync(() -> {
            /**设置车辆归属站点和车辆运维占用信息*/
            this.setParkAndOccupy(machineInfo);
        },threadPoolTaskExecutor).exceptionally(e -> {
            log.info("getMachineInfoV2------>获取车辆归属站点和车辆运维占用信息异常:e",e);
            return null;
        });
        CompletableFuture<Void> runFuture3 = CompletableFuture.runAsync(() -> {
            /**设置车辆功能*/
            this.setMachineFunction(machineInfo);
        },threadPoolTaskExecutor).exceptionally(e -> {
            log.info("getMachineInfoV2------>获取车辆功能异常:e",e);
            return null;
        }).thenRunAsync(() -> {
            /**故障信息*/
            this.setMachineFault(machineInfo);
        },threadPoolTaskExecutor).exceptionally(e -> {
            log.info("getMachineInfoV2------>获取车辆故障信息异常:e",e);
            return null;
        });
        CompletableFuture<Void> runFuture4 = CompletableFuture.runAsync(() -> {
            /**换电信息*/
            this.setMachineLastPowerChange(machineInfo);
        },threadPoolTaskExecutor).exceptionally(e -> {
            log.info("getMachineInfoV2------>获取车辆最新换电信息异常:e",e);
            return null;
        }).thenRunAsync(() -> {
            /**挪车信息*/
            this.setMachineLastMove(machineInfo);
        },threadPoolTaskExecutor).exceptionally(e -> {
            log.info("getMachineInfoV2------>获取车辆最新挪车信息异常:e",e);
            return null;
        }).thenRunAsync(() -> {
            /**调度信息*/
            this.setMachineLastDispatch(machineInfo);
        },threadPoolTaskExecutor).exceptionally(e -> {
            log.info("getMachineInfoV2------>获取车辆最新调度信息异常:e",e);
            return null;
        });
        CompletableFuture.allOf(runFuture1,runFuture2,runFuture3,runFuture4).join();
        return machineInfo;
    }

    /**
     * @description: 设置车辆的库存信息和标签信息
     * @author: mo.shanyong
     * @date: 2025/4/18 9:14
     * @param: machineInfo
     * @param: machine 车辆
     */
    private void setMachineStockAndTag(MachineInfo machineInfo){
        Machine machine = machineInfo.getMachine();
        List<TagBaseInfo> tagBaseInfos = tagDao.getTagByMachineId(machine.getMachineId());
        if (CollectionUtils.isNotEmpty(tagBaseInfos)) {
            machineInfo.setBindTags(tagBaseInfos);
            machineInfo.parse();
        }
        MachineStatusBorrow machineStatusBorrow = new MachineStatusBorrow();
        machineStatusBorrow.setLastBorrowTime(machine.getLastBorrowTime());
        // 库存状态，0：不在库存，1：在库存
        Integer stock = stockMachineService.countByMachineId(machine.getMachineId());
        machineStatusBorrow.setStock(stock > 0);
        machineInfo.setMachineStatusBorrow(machineStatusBorrow);
    }

    /**
     * @description: 设置车辆状态信息
     * @author: mo.shanyong
     * @date: 2025/4/18 9:21
     * @param: machineInfo
     */
    private void setMachineState(MachineInfo machineInfo){
        Machine machine = machineInfo.getMachine();
        Integer machineId = machine.getMachineId();
        MachineShowStatus machineShowStatus = new MachineShowStatus();
        machineShowStatus.setMachineBusState(1);
        machineShowStatus.setMachineMainState(machine.getState());
        machineShowStatus.setMachineLockState(1);
        machineShowStatus.setMachineParkState(1);
        MachineStatus machineStatus = machineStatusService.getByMachineId(machineId);
        if (machineStatus != null) {
            /**用户码、中控码*/
            machineStatus.setUserCode(machine.getUserCode());
            machineStatus.setMachineNO(machine.getMachineNO());

            Battery battery = batteryService.getByMachineId(machineInfo.getMachine().getMachineId());
            if (battery != null) {
                machineStatus.setBatteryNO(battery.getBatteryNO());
                machineInfo.getMachine().setBatteryNO(battery.getBatteryNO());
            }
            machineInfo.setMachineStatus(machineStatus);

            /**查询车辆锁状态*/
            String json = redisService.getGetWay(RedisUtil.getTerHashId(machine.getMachineNO()), RedisConstant.REDIS_TER_LAST_STATUS);
            TerLastStatus terLastStatus = JSONObject.parseObject(json, TerLastStatus.class);
            Boolean lock;
            if (terLastStatus == null) {
                lock = IntegerUtil.getLockState(0);//无信号车辆
            } else {

                lock = IntegerUtil.getLockState(terLastStatus.getCarStatus());
            }

            machineShowStatus.setMachineLockState(lock ? 1 : 0);
        } else {
            throw new BaseException("MachineState.not.gps");
        }
        //检查车辆展示状态
        this.checkMachineShowStatus(machineShowStatus,machineStatus,machine);
        //车辆异常信息
        MachineAbnormal machineAbnormal = machineAbnormalService.getByMachineIdAndType(machine.getMachineId(), MachineAbnormalConstant.MACHINE_ABNORMAL_CCQY);
        if (machineAbnormal != null) {
            machineInfo.getMachineStatus().setAbnormalTime(machineAbnormal.getAbnormalTime());
        }
        //头盔锁信息
        Helmet helmet = helmetBoundService.getMachineId(machine.getMachineId());
        if (helmet != null) {
            machineInfo.getMachineStatus().setHelmetSoc(helmet.getSoc());
            machineInfo.getMachine().setHelmetMac(helmet.getHelmetMac());
        }
        /**查询车辆绑定电池类型id*/
        this.setBatteryState(machineInfo);

        machineInfo.setMachineShowStatus(machineShowStatus);
    }

    /**
     * @description: 检查车辆展示状态
     * @author: mo.shanyong
     * @date: 2025/4/18 9:45
     * @param: machineShowStatus
     * @param: machineStatus
     * @param: machine
     */
    private void checkMachineShowStatus(MachineShowStatus machineShowStatus,MachineStatus machineStatus,Machine machine){
        Integer machineId = machine.getMachineId();
        /**查询车辆当前租车信息*/
        MachineBorrow machineBorrow = machineBorrowService.getByMachineId(machineId);
        if (machineBorrow != null) {
            machineShowStatus.setMachineBusState(2);
            /**查询车辆临停信息*/
            Park park = getParkByMachineId(machineId);
            if (park != null) {
                machineShowStatus.setMachineBusState(3);
            }
        }
        /**检测是否在站点*/
        /**是否在区域内*/
        if (machineStatus != null) {
            List<Geo> geos = geoService.getByAccountId(machine.getAccountId());
            if (geos.size() > 0) {
                Geo geo = geos.get(0);
                Boolean isInArea = GeoUtil.IsPtInPoly(new Point(machineStatus.getLon(), machineStatus.getLat()), GeoUtil.getPoints(geo.getPoints()));
                //0:站外；1：站内；2：超区
                if (isInArea) {
                    /**判断是站外还是禁停区内*/
                    AccountConfig ac = accountConfigService.getByAccountId(machine.getAccountId());
                    if (ac == null || ac.getReturnModel() == 0) {
                        ParkPoint parkPointIn = parkPointService.checkInParkPoint(machine.getAccountId(), new Point(machineStatus.getLon(), machineStatus.getLat()), 150, 100);
                        machineShowStatus.setMachineParkState(parkPointIn == null ? 0 : 1);
                    } else {
                        /**判断是否禁停区内*/
                        ProhibitArea prohibitArea = prohibitAreaService.checkInProhibitArea(machine.getAccountId(), new Point(machineStatus.getLon(), machineStatus.getLat()), 3000);
                        machineShowStatus.setMachineParkState(prohibitArea == null ? 0 : 1);
                    }
                } else {
                    machineShowStatus.setMachineParkState(2);
                }
            }
        }
    }

    /**
     * @description: 设置车辆的电池信息
     * @author: mo.shanyong
     * @date: 2025/4/18 9:59
     * @param: machineInfo
     */
    private void setBatteryState(MachineInfo machineInfo){
        MachineBatteryModel machineBatteryModel = batteryModelService.getMachineId(machineInfo.getMachine().getMachineId());
        if (machineBatteryModel != null) {

            /**查询主电池方案*/
            BatteryModel batteryModel = batteryModelService.getByModelId(machineBatteryModel.getBatteryModelId());
            if (batteryModel != null) {
                machineInfo.getMachineStatus().setBatteryType(batteryModel.getBatteryType());
                //电池方案名称
                machineInfo.getMachine().setBatteryName(batteryModel.getName());
            } else {
                machineInfo.getMachineStatus().setBatteryType(BatteryConstant.Battery_type_dy);
            }

            //判断主电池是否为氢电池
            if (batteryModel != null && Objects.equals(BatteryConstant.Battery_type_qdc, batteryModel.getBatteryType())) {
                if (machineBatteryModel.getSecondaryBattertId() != null) {
                    //查询电压
                    MachineEvent machineEvent = machineAttrService.getMachineEvent(machineInfo.getMachine().getMachineNO(), "tLiSOC");
                    Integer secondaryBattery = Optional.ofNullable(machineEvent)
                            .map(MachineEvent::getEventValue)
                            .filter(StringUtils::isNotBlank)
                            .map(Integer::parseInt)
                            .orElse(0);
                    machineInfo.getMachineStatus().setSecondaryBattery(secondaryBattery);

                }
            }
        }
    }

    /**
     * @description: 获取最新车辆订单
     * @author: mo.shanyong
     * @date: 2025/4/18 9:47
     * @param: machineInfo
     */
    private void setLastRideLog(MachineInfo machineInfo) throws ParseException {
        Integer machineId = machineInfo.getMachine().getMachineId();
        RideLog rideLog = rideLogService.findLastByMachineId(machineId);
        if (rideLog != null) {
            /**计算骑行时长*/
            String startTime = rideLog.getStartTime();
            String endTime = DateTimeUtil.getNowTime();
            MachineBorrow machineBorrow = machineBorrowService.getByMachineId(machineId);
            if (machineBorrow == null && rideLog.getEndTime() != null) {
                endTime = rideLog.getEndTime();
            }

            Integer rideTime = DateTimeUtil.getMinutes(startTime, endTime);
            rideLog.setRideTime(rideTime);

            machineInfo.setRideLog(rideLog);
        }
    }

    /**
     * @description: 设置车辆归属站点和车辆运维占用信息
     * @author: mo.shanyong
     * @date: 2025/4/18 9:49
     * @param: machineInfo
     */
    private void setParkAndOccupy(MachineInfo machineInfo){
        Integer machineId = machineInfo.getMachine().getMachineId();
        /**查询归属站点信息*/
        ParkPoint parkPoint = parkPointService.getByMachineId(machineId);
        if (parkPoint != null) {
            machineInfo.setParkPoint(parkPoint);
        }
        /**车辆运维占用信息*/
        MachineOccupy machineOccupy = machineOccupyService.getByMachineId(machineId);
        if (machineOccupy != null) {
            AccountUser au = accountUserService.getById(machineOccupy.getAccountUserId());
            if (au != null) {
                machineOccupy.setName(au.getName());
            }

            machineInfo.setMachineOccupy(machineOccupy);
        }
    }

    /**
     * @description: 设置车辆功能
     * @author: mo.shanyong
     * @date: 2025/4/18 10:01
     * @param: machineInfo
     */
    private void setMachineFunction(MachineInfo machineInfo){
        Integer machineId = machineInfo.getMachine().getMachineId();
        /**查询设备功能*/
        List<MachineFunction> machineFunctions = machineFunctionService.getMachineId(machineId);
        machineInfo.getMachine().setMachineFunctionList(machineFunctions);

        /**查询文明骑行摄像头*/
        Camera camera = cameraService.getMachineNO(machineInfo.getMachine().getMachineNO());
        machineInfo.getMachine().setCamera(camera);
    }

    /**
     * @description: 设置车辆故障信息
     * @author: mo.shanyong
     * @date: 2025/4/18 10:43
     * @param: machineInfo
     */
    private void setMachineFault(MachineInfo machineInfo){
        Machine machine = machineInfo.getMachine();
        MachineFault machineFault = machineFaultDao.getByMachineId(machine.getMachineId());
        if (Objects.isNull(machineFault)){
            return;
        }
        Map<String, List<String>> map = new HashMap<>();
        Set<String> faultNameSet = this.addFault(new ArrayList<>(Collections.singletonList(machineFault)), map);
        machineFault.setFaults(CollectionUtils.isNotEmpty(faultNameSet) ? String.join(",",faultNameSet) : machineFault.getFaults());
        machineInfo.setMachineFault(machineFault);
    }

    /**
     * @description: 设置最新一条换电记录信息
     * @author: mo.shanyong
     * @date: 2025/4/18 13:30
     * @param: machineInfo
     */
    private void setMachineLastPowerChange(MachineInfo machineInfo){
        Machine machine = machineInfo.getMachine();
        Map<String, Object> map = new HashMap<>();
        map.put("machineId", machine.getMachineId());
        List<PowerChangeLog> powerChangeLogList = powerChangeLogDao.getByMachineIdTime(map);
        if (CollectionUtils.isEmpty(powerChangeLogList)){
            return;
        }
        PowerChangeLog powerChangeLog = powerChangeLogList.get(0);
        AccountUser accountUser = accountUserService.getAccountUserById(powerChangeLog.getUserMainId());
        powerChangeLog.setUserMainName(Objects.nonNull(accountUser) ? accountUser.getName() : null);
        PowerChangeLogExpand powerChangeLogExpand = powerChangeLogExpandDao.getPowerChangeId(powerChangeLog.getPowerChangeLogId());
        if (Objects.nonNull(powerChangeLogExpand)){
            powerChangeLog.setBatteryNO(StringUtils.isBlank(powerChangeLog.getBatteryNO()) ? powerChangeLogExpand.getBatteryNONew() : powerChangeLog.getBatteryNO());
            powerChangeLog.setBatteryNOOld(powerChangeLog.getBatteryNOOld());
        }
        machineInfo.setLastPowerChangeLog(powerChangeLog);
    }
    /**
     * @description: 设置最新一条挪车记录
     * @author: mo.shanyong
     * @date: 2025/4/18 13:32
     * @param: machineInfo
     */
    private void setMachineLastMove(MachineInfo machineInfo){
        Machine machine = machineInfo.getMachine();
        MoveLog moveLog = moveLogDao.selectLastOneByMachineId(machine.getMachineId());
        if (moveLog != null) {
            Integer mapType = SysConstant.GOOGLE;
            calibrateService.calMoveLog(moveLog, MapConstant.MAP_ORI, mapType);

            /**计算挪车距离*/
            if (moveLog.getEndLon() != null && moveLog.getEndLat() != null) {
                Integer distance = historyService.getMileageByMachineNOAndTime(moveLog.getMachineNO(), moveLog.getStartTime(), moveLog.getEndTime());
                moveLog.setDistance(distance);
            }
            /**运维人员名称*/
            AccountUser accountUser = accountUserService.getAccountUserById(moveLog.getUserMainId());
            moveLog.setUserMainName(Objects.isNull(accountUser) ? null : accountUser.getName());

        }
        machineInfo.setLastMoveLog(moveLog);
    }

    /**
     * @description: 设置最新一条调度记录
     * @author: mo.shanyong
     * @date: 2025/4/18 13:32
     * @param: machineInfo
     */
    private void setMachineLastDispatch(MachineInfo machineInfo){
        Machine machine = machineInfo.getMachine();
        Map<String, Object> map = new HashMap<>();
        map.put("machineId", machine.getMachineId());
        List<DispatchLog> dispatchLogList = dispatchLogDao.getByMachineIdTime(map);
        if (CollectionUtils.isEmpty(dispatchLogList)){
            return;
        }
        DispatchLog dispatchLog = dispatchLogList.get(0);
        if (dispatchLog != null) {
            /**计算调度距离*/
            Integer distance = historyService.getMileageByMachineNOAndTime(dispatchLog.getMachineNO(), dispatchLog.getDispatchTime(), dispatchLog.getFinishTime());
            dispatchLog.setDistance(distance);

            if (dispatchLog.getAuditorId() == null || dispatchLog.getAuditorId().equals(WorkOrderConstant.sys_auditor)) {
                dispatchLog.setAuditorName(WorkOrderConstant.sys_auditorName);
            } else if (dispatchLog.getAuditorId() != null) {
                AccountUser accountUser = accountUserService.getById(dispatchLog.getAuditorId());
                dispatchLog.setAuditorName(accountUser.getName());
            }
            /**运维人员名称*/
            if (Objects.nonNull(dispatchLog.getUserMainId())){
                AccountUser accountUser = accountUserService.getAccountUserById(dispatchLog.getUserMainId());
                dispatchLog.setUserMainName(Objects.nonNull(accountUser) ? accountUser.getName() : null);
            }
        }
        machineInfo.setDispatchLog(dispatchLog);
    }



    @Override
    public void updateLastReturnTime(String machineNO, Date lastReturnTime) {
        machineDao.updateLastReturnTime(machineNO, lastReturnTime);
    }

    @Override
    public Machine getByUserCodeAndAccountId(String userCode, Integer accountId) {
        return machineDao.getByUserCodeAndAccountId(userCode, accountId);
    }
}